#ifndef ini_h
#define ini_h

/*
 *  Ini-parser and Regex library written by Chris McFarland
 *  You may use these resources freely as long as you attribute credit for them
 *  to me (Chris McFarland) and do not claim them as your own. You may not use
 *  my name to advertise your product.
 */

//clean this for real use
#ifdef FIGS_BUILD
#include <regex.h>
#else
#include "regex.h"
#endif

#include <map>
#include <string>
#include <fstream>
#include <stdexcept>

#include <algorithm>

using namespace std;

        extern regex letter;
        extern regex number;
        extern regex underscore;
        extern regex identifier;
        extern regex strchars;
        extern regex RxString;
        extern regex value;
        extern regex key;
        extern regex assign;
        extern regex comm_char;
        extern regex comment;

class ini
{
    typedef map<string,map<string,string> >::iterator ini_iterator;
    map<string,map<string,string> > data;
    const string empty;
public:
    ini(const string& filename) : empty("")
    {
        //yes, this style is bad...
        //but this is a quick program
        fstream file(filename.c_str());
        if(!file.good())
        {
            throw invalid_argument("Bad file: "+filename+ "\n");
        }
        string import;
        while(!file.eof() && file.good())
        {
            string foo;
            getline(file,foo,'\n');
            if((foo == empty) || (foo == "\n") || (foo == "\r\n") || (foo == "\r")) { continue; }
            import+=foo;
            import+='\n';

        }
        // Remove the trailing newline that borks things
        //import.erase(import.end() -1);
        file.close();

        //now we parse:

        string cur_key="";

        while(import.size()!=0)
        {
            match_result rez;
            rez = comment.match(import);
            if(rez)
            {
                import = string(import.begin()+rez.get_length(),import.end());
                continue;
            }

            rez = key.match(import);
            if(rez)
            {
                cur_key = rez.get(1).what;
                import = string(import.begin()+rez.get_length(),import.end());
                data.insert(pair<string,map<string,string> >(cur_key,map<string,string>()));
                continue;
            }

            rez = assign.match(import);
            if(rez)
            {
                if(cur_key=="")
                {
                    //replace this error with your own
                    cerr<<"Error: Missing section header in INI.\n";
                    abort();
                }

                data[cur_key][rez.get(0).what]=rez.get(2).what;
                import = string(import.begin()+rez.get_length(),import.end());
                continue;
            }

            //you should only get here if you have malformed assignements
            cerr<<"Error: Invalid file format -- invalid statements.\n";
            abort();
        }
    }


    const string& lookup(const string& address)
    {
        string section;
        string key_sect;

        match_result rez = (identifier >> term(':') >> identifier).match(address);

        if(rez)
        {
            section = rez.get(0).what;
            key_sect = rez.get(2).what;
        }
        else
        {
            return empty; //bad input, might want to replace this with an error
        }


        ini_iterator i = data.find(section);
        if(i==data.end())
        {
            return empty;
        }
        else
        {
            map<string,string>::iterator j;
            j = i->second.find(key_sect);
            if(j==i->second.end())
            {
                return empty;
            }
            else
            {
                return j->second;
            }
        }
    }
};

#endif
